//
//  AesDecryptor.m
//  aestest
//
//  Created by yaoziyang on 14-7-16.
//  Copyright (c) 2014年 yaoziyang. All rights reserved.
//

#import "AesDecryptor.h"

static const int BUFFER_LENGTH = 512;

@interface Decryptor()
{
@protected
    CCCryptorRef _cryptorRef;
    uint8_t* _outBuffer;
    
    CCAlgorithm _algorithm;
    CCOptions _paddingOptions;
    NSData* _key;
}
@end

@implementation Decryptor

- (CCAlgorithm)algorithm
{
    return _algorithm;
}

- (CCOptions)paddingOptions
{
    return _paddingOptions;
}

- (NSData*)key
{
    return _key;
}

- (id)init
{
    if (self = [super init])
    {
        _cryptorRef = NULL;
        _outBuffer = (uint8_t*)malloc(BUFFER_LENGTH);
        if (!_outBuffer)
            self = nil;
    }
    return self;
}

- (id)initWith:(CCAlgorithm)alg padding:(CCOptions)padOptions key:(NSData*)key
{
    if (self = [self init])
    {
        if (kCCSuccess != CCCryptorCreate(kCCDecrypt,
                            alg,
                            padOptions,
                            [key bytes],
                            [key length],
                            NULL,
                            &_cryptorRef))
        {
            self = nil;
        }
    }
    return self;
}

- (NSData*)accept:(const void *)dataIn inDataLen:(size_t) dataInLength
{
    return  nil;
}

- (NSData*)doFinal
{
    return nil;
}

- (void)dealloc
{
    if (_cryptorRef)
    {
        CCCryptorRelease(_cryptorRef);
    }
    
    if (_outBuffer)
    {
        free(_outBuffer);
    }
}

@end

@implementation Aes128Decryptor

- (NSData*)accept:(const void *)dataIn inDataLen:(size_t) dataInLength
{
    size_t decryptedLen = 0;
    
    if (kCCSuccess == CCCryptorUpdate(_cryptorRef, dataIn, dataInLength, _outBuffer, BUFFER_LENGTH, &decryptedLen))
    {
        if (decryptedLen > 0) {
            return [NSData dataWithBytes:_outBuffer length:decryptedLen];
        }
    }
    
    return nil;
}

- (NSData*)doFinal
{
    size_t decryptedLen = 0;
    
    if (kCCSuccess == CCCryptorFinal(_cryptorRef, _outBuffer, kCCBlockSizeAES128, &decryptedLen))
    {
        if (decryptedLen == 0)
            return nil;
        
        char padding = 0;
        
        if (self.paddingOptions == kCCOptionECBMode)
            padding = *(char*)(_outBuffer+decryptedLen-1);
        
        if (padding >= decryptedLen)
            return nil;
        
        return [NSData dataWithBytes:_outBuffer length:decryptedLen-padding];
    }
    
    return nil;
}

+ (BOOL)isValidKey:(NSData*)key
{
    int keySize = [key length];
    return keySize == 16 || keySize == 24 || keySize == 32;
}

+ (id)create:(NSData *)key
{
    if (![self isValidKey:key])
        return nil;
    
    return [[Aes128Decryptor alloc] initWith:kCCAlgorithmAES128 padding:kCCOptionECBMode key:key];
}

+ (id)create:(CCAlgorithm)alg padding:(CCOptions)op key:(NSData*)key
{
    if (![self isValidKey:key])
        return nil;
    
    return [[Aes128Decryptor alloc] initWith:kCCAlgorithmAES128 padding:op key:key];
}

@end
